package br.com.jk.cotacao.lancamento;

import br.com.jk.cotacao.*;
import br.com.jk.cotacao.itens.CotacaoItens;
import br.com.jk.produto.Produto;
import br.com.jk.util.DAOException;
import br.com.jk.util.pesquisa.Pesquisa.Opcao;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author camilo
 */
public class CotacaoLancamentoDaoHibernate implements CotacaoLancamentoDao {

  private Session session;
  private Transaction transacao;

  public void setSession(Session session) {
    this.session = session;
  }

  @Override
  public void salvar(CotacaoLancamento forn) throws DAOException {
    this.transacao = this.session.beginTransaction();
    this.session.saveOrUpdate(forn);
    this.transacao.commit();
    this.session.close();
  }

  @Override
  public void excluir(CotacaoLancamento forn) throws DAOException {
    this.transacao = this.session.beginTransaction();
    this.session.delete(forn);
    this.transacao.commit();
    this.session.close();
  }

  @Override
  public CotacaoLancamento carregar(int id) {
    return (CotacaoLancamento) this.session.get(CotacaoLancamento.class, id);
  }

  @Override
  public Integer ultimoNumLancamento() {
    try {
      Criteria criteria = this.session.createCriteria(CotacaoLancamento.class);
      criteria.addOrder(Order.desc(CotacaoLancamento.ATTRIBUTE_NUM_LANCAMENTO));
      criteria.setMaxResults(1);
      CotacaoLancamento cl = (CotacaoLancamento) criteria.uniqueResult();
      return cl.getNumLancamento();
    } catch (NullPointerException e) {
      return 0;
    }
  }

  @Override
  public List<CotacaoLancamento> listar(Integer numLancamento) {
    return this.session.createCriteria(CotacaoLancamento.class)
            .add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_NUM_LANCAMENTO, numLancamento))
            .addOrder(Order.asc(CotacaoLancamento.ATTRIBUTE_PRODUTO)).list();
  }
  
  @Override
  public List<CotacaoLancamento> listar(Produto produto, Cotacao cotacao, CotacaoItens cotacaoItens){
    Criteria criteria = this.session.createCriteria(CotacaoLancamento.class);
    criteria.setFetchMode(CotacaoLancamento.ATTRIBUTE_PRODUTO, FetchMode.JOIN).add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_PRODUTO, produto));
    criteria.setFetchMode(CotacaoLancamento.ATTRIBUTE_COTACAO, FetchMode.JOIN).add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_COTACAO, cotacao));
    criteria.setFetchMode(CotacaoLancamento.ATTRIBUTE_COTACAOITENS, FetchMode.JOIN).add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_COTACAOITENS, cotacaoItens));
    return criteria.list();
  }

  /**
   * Retorna um objeto criteria com o "Restriction" de acordo a necessidade do usuário <br />
   * <br />
   * Os parâmetros <i>strCrit </i>e<i> dateCrit</i> podem ser declarados como <b>null</b>
   * e o parâmetro <i>intCrit </i> pode ser declarado 0, mas ao menos um dos três precisa ter um
   * valor válido especificado.<br />
   * <br />
   * Caso não seja definida uma opção a opção padrão é <i>CONTENDO</i>
   * e o critério usado será o <i>strCrit</i>
   *
   * @param property Nome do atributo mapeado
   * @param opcao Tipo da pesquisa (contendo, igual, maior, etc)
   * @param strCrit Caso não possua defina null
   * @param intCrit Caso não possua defina 0
   * @param dateCrit Caso não possua defina null
   *
   * @return Criteria
   */
  private Criteria getCriteriaOpcao(String property, Opcao opcao, String strCrit, int intCrit) {
    Criteria criteria = this.session.createCriteria(CotacaoLancamento.class);
    switch (opcao) {
      case CONTENDO:
        criteria.add(Restrictions.ilike(property, strCrit, MatchMode.ANYWHERE));
        break;
      case DIFERENTE:
        if (strCrit == null && intCrit > -1) {
          criteria.add(Restrictions.ne(property, intCrit));
        } else {
          criteria.add(Restrictions.ne(property, strCrit));
        }
        break;
      case IGUAL:
        if (strCrit == null && intCrit > -1) {
          criteria.add(Restrictions.eq(property, intCrit));
        } else {
          criteria.add(Restrictions.eq(property, strCrit));
        }
        break;
      case INICIA:
        criteria.add(Restrictions.ilike(property, strCrit, MatchMode.START));
        break;
      case MAIOR:
        criteria.add(Restrictions.ge(property, intCrit));
        break;
      case MENOR:
        criteria.add(Restrictions.le(property, intCrit));
        break;
      case TERMINA:
        criteria.add(Restrictions.ilike(property, strCrit, MatchMode.END));
        break;
    }
    return criteria;
  }

  @Override
  public List<CotacaoLancamento> pesquisaPadrao(Cotacao cotacao, String property, String criterio, Opcao opcao) {
    Criteria criteria = getCriteriaOpcao(property, opcao, criterio, 0);
    criteria.add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_COTACAOITENS, cotacao));
    criteria.addOrder(Order.asc(property));
    return criteria.list();
  }

  @Override
  public List<CotacaoLancamento> pesquisaPadrao(Cotacao cotacao, String property, int criterio, Opcao opcao) {
    Criteria criteria = getCriteriaOpcao(property, opcao, null, criterio);
    criteria.add(Restrictions.eq(CotacaoLancamento.ATTRIBUTE_COTACAOITENS, cotacao));
    criteria.addOrder(Order.asc(property));
    return criteria.list();
  }
}
